package br.com.gip.controller;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map.Entry;

import javax.faces.model.SelectItem;

import org.richfaces.component.html.HtmlDataList;
import org.richfaces.component.html.HtmlDataTable;
import org.richfaces.event.DropEvent;
import org.richfaces.model.TreeNode;
import org.richfaces.model.TreeNodeImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Controller;

import br.com.gip.business.ArtefatoBusiness;
import br.com.gip.business.CategoriaBusiness;
import br.com.gip.business.ProjetoBusiness;
import br.com.gip.business.RelacionamentoBusiness;
import br.com.gip.repository.model.Artefato;
import br.com.gip.repository.model.Categoria;
import br.com.gip.repository.model.Projeto;
import br.com.gip.repository.model.Relacionamento;
import br.com.gip.tree.Node;
import br.com.gip.wrapper.RelacionamentoArtefato;

@Scope("session")
@Controller("relacionamentoController")
public class RelacionamentoController implements Serializable {

	private static final long serialVersionUID = -5861256302725146343L;

	@Autowired
	private ProjetoBusiness projetoBusiness;

	@Autowired
	private ArtefatoBusiness artefatoBusiness;

	@Autowired
	private CategoriaBusiness categoriaBusiness;
	
	@Autowired
	private RelacionamentoBusiness relacionamentoBusiness;
	
	private String message;
	
	private Projeto projeto;
	
	private Long categoriaId;
	
	private String nomeArtefato;

	private TreeNode<Node> artefatos;
	
	private List<Node> artefatosOrigem;
	
	private List<Node> artefatosDestino;

	private List<RelacionamentoArtefato> relacionamentos;
	
	private HtmlDataTable dataTableOrigem;	
	
	private HtmlDataTable dataTableDestino;
	
	private HtmlDataList dataList;

	private RelacionamentoArtefato relacionamentoArtefato;
	
	private boolean editar;
	
	public RelacionamentoController() {
		this.reset();
	}
	
	public void buscarArtefatos() {
		this.artefatos = new TreeNodeImpl<Node>();
		
		if (this.projeto.getProjetoId() != null && this.projeto.getProjetoId() > 0) {
			for (Entry<Categoria, List<Artefato>> entry : this.artefatoBusiness.buscarArtefatos(this.projeto).entrySet()) {
				Categoria categoria = entry.getKey();
				
				TreeNode<Node> node = new TreeNodeImpl<Node>();
				node.setData(new Node(categoria.getNome(), "categoria"));
				this.artefatos.addChild(categoria.getCategoriaId(), node);
				
				for (Artefato artefato : entry.getValue()) {
					Node nodeFolha = new Node(artefato.getNome(), "artefato", artefato.getArtefatoId(), categoria.getCategoriaId(), artefato);
					if (!this.artefatosOrigem.contains(nodeFolha) && !this.artefatosDestino.contains(nodeFolha)) {
						TreeNode<Node> child = new TreeNodeImpl<Node>();
					    child.setData(nodeFolha);
					    node.addChild(artefato.getArtefatoId(), child);
					}
				}
			}
		}
	}
	
	public void processDropOrigem(DropEvent dropEvent) {
		if (this.artefatosOrigem.isEmpty()) {
			Node node = (Node) dropEvent.getDragValue();
			this.artefatosOrigem.add(node);
			this.artefatos.getChild(node.getParentId()).removeChild(node.getNodeId());
			this.message = "";
		} else {
			this.message = "E permitido somente um artefato mandatorio.";
		}
	}
	
	public void processDropDestino(DropEvent dropEvent) {
		if (this.artefatosOrigem.isEmpty()) {
			this.message = "Informe primeiro um artefato mandatorio.";
			return;
		}
		
		Node node = (Node) dropEvent.getDragValue();
		Artefato mandatorio = this.artefatosOrigem.get(0).getArtefato();
		
		if (mandatorio.isRestrito() && !mandatorio.getProjeto().getProjetoId().equals(node.getArtefato().getProjeto().getProjetoId())) {
			this.message = "O artefato mandatorio " + mandatorio.getNome() + " so pode se relacionar com artefatos do projeto " + mandatorio.getProjeto().getNome() + ".";
			return;
		}
		
		if (node.getArtefato().isRestrito() && !node.getArtefato().getProjeto().getProjetoId().equals(mandatorio.getProjeto().getProjetoId())) {
			this.message = "O artefato " + node.getNome() + " so pode se relacionar com artefatos do projeto " + node.getArtefato().getProjeto().getNome() + ".";
			return;
		}
		
		this.artefatosDestino.add(node);
		this.artefatos.getChild(node.getParentId()).removeChild(node.getNodeId());
		this.message = "";
	}
	
	public void removerOrigem() {
		Node node = (Node) this.dataTableOrigem.getRowData();
		this.artefatosOrigem.remove(node);
		this.artefatosDestino = new ArrayList<Node>();
		
		if (this.projeto.getProjetoId().equals(node.getArtefato().getProjeto().getProjetoId())) {
			TreeNode<Node> child = new TreeNodeImpl<Node>();
			child.setData(node);
			this.artefatos.getChild(node.getParentId()).addChild(node.getNodeId(), child);
		}
		
		this.message = "Os artefatos de destino foram removidos por garantia de integridade do relacionamento.";
	}

	public void removerDestino() {
		Node node = (Node) this.dataTableDestino.getRowData();
		this.artefatosDestino.remove(node);
		
		if (this.projeto.getProjetoId().equals(node.getArtefato().getProjeto().getProjetoId())) {
			TreeNode<Node> child = new TreeNodeImpl<Node>();
			child.setData(node);
			this.artefatos.getChild(node.getParentId()).addChild(node.getNodeId(), child);
		}

		if (this.editar) {
			this.relacionamentoArtefato.moverRelacionamento(node.getArtefato());
		}
		
		this.message = "";
	}

	public String cadastro() {
		this.reset();
		return "cadastro-relacionamento";
	}

	public String cadastrarRelacionamento() {
		String foward = "cadastro-relacionamento-sucesso";
		
		List<Relacionamento> relacionamentos = new ArrayList<Relacionamento>();
		
		Artefato origem = this.artefatosOrigem.get(0).getArtefato();
		for (Node node : this.artefatosDestino) {
			relacionamentos.add(new Relacionamento(origem, node.getArtefato()));
		}

		if (this.editar) {
			this.relacionamentoBusiness.removerRelacionamentos(this.relacionamentoArtefato.getRemovidos());
			this.relacionamentos = this.relacionamentoBusiness.buscarRelacionamentos(null, null, null);
			
			/* seta ID nos relacionamentos que nao foram removidos */
			for (Relacionamento relacionamento : relacionamentos) {
				this.relacionamentoArtefato.setRelacionamentoId(relacionamento);
			}
			
			foward = "lista-relacionamento";
		} else {
			this.reset();
			this.message = "Relacionamentos cadastrados com sucesso";	
		}
		
		this.relacionamentoBusiness.salvarRelacionamentos(relacionamentos);

		return foward;
	}
	
	public String lista() {
		this.reset();
		this.relacionamentos = null;
		return "lista-relacionamento";
	}

	public String buscarRelacionamentos() {
		this.reset();
		this.relacionamentos = this.relacionamentoBusiness.buscarRelacionamentos(this.nomeArtefato, this.categoriaId, this.projeto.getProjetoId());
		return "lista-relacionamento";
	}
	
	public String editarRelacionamento() {
		this.relacionamentoArtefato = (RelacionamentoArtefato) this.dataList.getRowData();

		/* popula a lista de artefatos origem */
		Artefato origem = this.relacionamentoArtefato.getOrigem();
		this.artefatosOrigem = Arrays.asList(new Node(origem.getNome(), "artefato", origem.getArtefatoId(), origem.getCategoria().getCategoriaId(), origem));

		/* popula a lista de artefatos destino */
		this.artefatosDestino = new ArrayList<Node>();
		for (Artefato artefato : this.relacionamentoArtefato.getDestinos()) {
			this.artefatosDestino.add(new Node(artefato.getNome(), "artefato", artefato.getArtefatoId(), artefato.getCategoria().getCategoriaId(), artefato));
		}
		
		this.editar = true;
		
		return "editar-relacionamento";
	}
	
	public SelectItem[] getAllProjetos() {
		List<SelectItem> itens = new ArrayList<SelectItem>();
		
		itens.add(new SelectItem("", "Selecione"));
		for (Projeto projeto : this.projetoBusiness.buscarProjetos()) {
			itens.add(new SelectItem(projeto.getProjetoId(), projeto.getNome()));
		}

		return itens.toArray(new SelectItem[itens.size()]);
	}

	public SelectItem[] getAllCategorias() {
		List<SelectItem> itens = new ArrayList<SelectItem>();
		
		itens.add(new SelectItem("", "Selecione"));
		for (Categoria categoria : this.categoriaBusiness.buscarCategorias()) {
			itens.add(new SelectItem(categoria.getCategoriaId(), categoria.getNome()));
		}

		return itens.toArray(new SelectItem[itens.size()]);
	}
	
	private void reset() {
		this.message = "";
		this.projeto = new Projeto();
		this.nomeArtefato = ""; 
		this.categoriaId = null;
		this.artefatos = new TreeNodeImpl<Node>();
		this.artefatosOrigem = new ArrayList<Node>();
		this.artefatosDestino = new ArrayList<Node>();
		this.editar = false;
	}
	
	public String getMessage() {
		return message;
	}

	public void setMessage(String message) {
		this.message = message;
	}

	public Projeto getProjeto() {
		return projeto;
	}

	public void setProjeto(Projeto projeto) {
		this.projeto = projeto;
	}

	public String getNomeArtefato() {
		return nomeArtefato;
	}

	public void setNomeArtefato(String nomeArtefato) {
		this.nomeArtefato = nomeArtefato;
	}

	public Long getCategoriaId() {
		return categoriaId;
	}

	public void setCategoriaId(Long categoriaId) {
		this.categoriaId = categoriaId;
	}
	
	public TreeNode<Node> getArtefatos() {
		return artefatos;
	}

	public void setArtefatos(TreeNode<Node> artefatos) {
		this.artefatos = artefatos;
	}

	public List<Node> getArtefatosOrigem() {
		return artefatosOrigem;
	}

	public void setArtefatosOrigem(List<Node> artefatosOrigem) {
		this.artefatosOrigem = artefatosOrigem;
	}

	public List<Node> getArtefatosDestino() {
		return artefatosDestino;
	}

	public void setArtefatosDestino(List<Node> artefatosDestino) {
		this.artefatosDestino = artefatosDestino;
	}

	public List<RelacionamentoArtefato> getRelacionamentos() {
		return relacionamentos;
	}

	public void setRelacionamentos(List<RelacionamentoArtefato> relacionamentos) {
		this.relacionamentos = relacionamentos;
	}

	public HtmlDataTable getDataTableOrigem() {
		return dataTableOrigem;
	}

	public void setDataTableOrigem(HtmlDataTable dataTableOrigem) {
		this.dataTableOrigem = dataTableOrigem;
	}

	public HtmlDataTable getDataTableDestino() {
		return dataTableDestino;
	}

	public void setDataTableDestino(HtmlDataTable dataTableDestino) {
		this.dataTableDestino = dataTableDestino;
	}

	public HtmlDataList getDataList() {
		return dataList;
	}

	public void setDataList(HtmlDataList dataList) {
		this.dataList = dataList;
	}

	public boolean isEditar() {
		return editar;
	}

	public void setEditar(boolean editar) {
		this.editar = editar;
	}

}
